// ignore_for_file: unnecessary_brace_in_string_interps, avoid_print

import 'dart:io';
import 'package:cookie_jar/cookie_jar.dart';
import 'package:dio/adapter.dart';
import 'package:dio/dio.dart';
import 'package:dio_cookie_manager/dio_cookie_manager.dart';
import 'package:dio_http2_adapter/dio_http2_adapter.dart';
import 'dart:convert';

enum DioMethod {
  get,
  post,
  put,
  delete,
  patch,
  head,
}

class DioManager {
  /// 连接超时时间
  static const int CONNECT_TIMEOUT = 10 * 1000;

  /// 响应超时时间
  static const int RECEIVE_TIMEOUT = 10 * 1000;

  /// 请求的URL前缀
  static String BASE_URL = "";

  /// 是否开启网络缓存,默认false
  static bool CACHE_ENABLE = false;

  /// 最大缓存时间(按秒), 默认缓存七天,可自行调节
  static int MAX_CACHE_AGE = 7 * 24 * 60 * 60;

  /// 最大缓存条数(默认一百条)
  static int MAX_CACHE_COUNT = 100;

  static DioManager? _instance;
  static Dio _dio = Dio();
  Dio get dio => _dio;

  DioManager._internal() {
    _instance = this;
    _instance!._init();
  }

  factory DioManager() => _instance ?? DioManager._internal();

  static DioManager? getInstance() {
    _instance ?? DioManager._internal();
    return _instance;
  }

  /// 取消请求token
  CancelToken _cancelToken = CancelToken();

  /// cookie
  CookieJar cookieJar = CookieJar();

  _init() {
    /// 初始化基本选项
    BaseOptions options = BaseOptions(
        baseUrl: BASE_URL,
        connectTimeout: CONNECT_TIMEOUT,
        receiveTimeout: RECEIVE_TIMEOUT);

    /// 初始化dio
    _dio = Dio(options);

    /// 添加cookie管理器
    _dio.interceptors.add(LogInterceptor(responseBody: true));
  }

  /// 设置Http代理(设置即开启)
  void setProxy({String? proxyAddress, bool enable = false}) {
    if (enable) {
      (_dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =
          (HttpClient client) {
        client.findProxy = (uri) {
          return proxyAddress ?? "";
        };
        client.badCertificateCallback =
            (X509Certificate cert, String host, int port) => true;
      };
    }
  }

  /// 设置https证书校验
  void setHttpsCertificateVerification({String? pem, bool enable = false}) {
    if (enable) {
      (_dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =
          (client) {
        client.badCertificateCallback =
            (X509Certificate cert, String host, int port) {
          if (cert.pem == pem) {
            // 验证证书
            return true;
          }
          return false;
        };
      };
    }
  }

  /// 开启日志打印
  void openLog() {
    _dio.interceptors.add(LogInterceptor(responseBody: true));
  }

  /// 请求类
  void request(String path,
      {DioMethod method = DioMethod.get,
      Map<String, dynamic>? params,
      data,
      CancelToken? cancelToken,
      Options? options,
      ProgressCallback? onSendProgress,
      ProgressCallback? onReceiveProgress,
      required Function successCallBack,
      required Function errorCallBack}) async {
    const methodValues = {
      DioMethod.get: 'get',
      DioMethod.post: 'post',
      DioMethod.put: 'put',
      DioMethod.delete: 'delete',
      DioMethod.patch: 'patch',
      DioMethod.head: 'head'
    };
    Response response;
    options ??= Options(method: methodValues[method]);
    try {
      response = await _dio.request(path,
          data: data,
          queryParameters: params,
          cancelToken: cancelToken ?? _cancelToken,
          options: options,
          onSendProgress: onSendProgress,
          onReceiveProgress: onReceiveProgress);
    } on DioError catch (e) {
      errorCallBack(e);
      rethrow;
    }
    if (response.data != null) {
      if (response.data is String) {
        successCallBack(response.data);
      } else {
        String dataStr = response.toString();
        Map<String, dynamic> dataMap = json.decode(dataStr);
        dataMap = responseFactory(dataMap);
        if (dataMap["code"] == 401) {
          errorCallBack(dataMap);
        } else {
          successCallBack(dataMap);
        }
      }
    }
  }

  /// 单独请求post
  void postUrl(String path, String? token,
      {DioMethod method = DioMethod.post,
      Map<String, dynamic>? params,
      data,
      CancelToken? cancelToken,
      Options? options,
      ProgressCallback? onSendProgress,
      ProgressCallback? onReceiveProgress,
      required Function successCallBack,
      required Function errorCallBack}) async {
    _dio.options.baseUrl = path;
    _dio.options.headers = {
      'contentType': 'application/x-www-form-urlencoded',
      'x-ds-key': token
    };
    Response response;
    try {
      response = await dio.post(
        '',
        data: {},
        queryParameters: params,
        options: Options(
          contentType: Headers.jsonContentType,
        ),
      );
      if (response.data != null) {
        String dataStr = response.toString();
        Map<String, dynamic> dataMap = json.decode(dataStr);
        dataMap = responseFactory(dataMap);
        if (dataMap["code"] == 401) {
          errorCallBack(dataMap);
        } else {
          successCallBack(dataMap);
        }
      }
    } on DioError catch (e) {
      errorCallBack(e);
      rethrow;
    }
  }

  Map<String, dynamic> responseFactory(Map<String, dynamic> dataMap) {
    return dataMap;
  }

  /// 取消网络请求
  void cancelRequests({CancelToken? token}) {
    token ?? _cancelToken.cancel("cancelled");
  }
}
